/*
 * KKAudioPlayer.cpp
 *
 *  Created on: 2013-9-15
 *      Author: wanghua
 */

#include "KKAudioPlayer.h"

#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "string.h"

void ERRCHECKWITHEXIT(FMOD_RESULT result) {
	if (result != FMOD_OK) {
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
		//		exit(-1);
	}
}

bool ERRCHECK(FMOD_RESULT result) {
	if (result != FMOD_OK) {
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
		return true;
	}
	return false;
}

FMOD::System* KKAudioPlayer::pSystem = NULL;

KKAudioPlayer::KKAudioPlayer() {
	m_sound = NULL;
	m_channel = NULL;
	m_channelGroup = NULL;

	m_endCallback = NULL;

	m_simple = false;
	m_removeCallback = true;
}

KKAudioPlayer::~KKAudioPlayer() {
	destory();
	m_sound = NULL;
	m_channel = NULL;
	m_channelGroup = NULL;

	if (m_endCallback) {
		m_endCallback->release();
		m_endCallback = NULL;
	}

	m_soundPath.clear();
}

void KKAudioPlayer::initAudioSystem() {
	if (!pSystem) {
		//init
		FMOD_RESULT result;

		unsigned int version;
		/*
		 Create a System object and initialize.
		 */
		result = FMOD::System_Create(&pSystem);
		ERRCHECKWITHEXIT(result);

		result = pSystem->getVersion(&version);
		ERRCHECKWITHEXIT(result);

		CCLog("fmod version %d \n", (int) version);

		result = pSystem->setOutput(FMOD_OUTPUTTYPE_AUTODETECT);
		ERRCHECKWITHEXIT(result);

		result = pSystem->init(32, FMOD_INIT_NORMAL, 0);
		ERRCHECKWITHEXIT(result);
	}
}

void KKAudioPlayer::updateAudioSystem() {
	if (pSystem) {
		pSystem->update();
	}
}

void KKAudioPlayer::destoryAudioSystem() {
	if (pSystem) {
		FMOD_RESULT result;
		result = pSystem->close();
		ERRCHECKWITHEXIT(result);
		result = pSystem->release();
		ERRCHECKWITHEXIT(result);
	}
}

void KKAudioPlayer::load(const char* soundPath) {

	FMOD_RESULT result;

	pSystem->update();

	if (m_sound && m_soundPath != soundPath) {

		result = m_sound->release();

		ERRCHECKWITHEXIT(result);

		m_sound = NULL;
	}

	m_soundPath = soundPath;

	if (!m_sound) {
		//result = pSystem->createSound(soundPath, FMOD_LOOP_NORMAL, 0, &m_sound);

#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
		unsigned long int length = 0;
		unsigned char* data = CCFileUtils::getFileData(soundPath,"rb",&length);

		if(length>0) {
			FMOD_CREATESOUNDEXINFO exinfo;
			memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
			exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
			exinfo.length = length;
			result = pSystem->createSound((const char*)data,FMOD_OPENMEMORY | FMOD_LOOP_NORMAL, &exinfo, &m_sound);
			CC_SAFE_DELETE_ARRAY(data);
		}

#else
		result = pSystem->createStream(soundPath, FMOD_LOOP_NORMAL, 0,
				&m_sound);
		//result = pSystem->createStream("/mnt/sdcard/begin_bg.mp3", FMOD_LOOP_NORMAL, 0, &m_sound);

#endif

		ERRCHECK(result);
	}

}

void KKAudioPlayer::setSoundPath(string soundPath) {
	if (m_soundPath != soundPath) {
		stop();
		load(soundPath.c_str());
		if (isPlaying()) {
			play(m_loop);
		}
		m_soundPath = soundPath;
	}
}

string KKAudioPlayer::getSoundPath() {
	return m_soundPath;
}

float KKAudioPlayer::getDuration() {

	if (!m_sound) {
		return -2;
	}

	unsigned int len;

	m_sound->getLength(&len, FMOD_TIMEUNIT_MS);

	return int(len) / 1000.0f;
}

bool KKAudioPlayer::isPlaying() {
	bool bPlaying;
	if (m_channel == NULL) {
		return false;
	}
	pSystem->update();

	//printf("isPlaying %s\n", m_soundPath.c_str());

	FMOD_RESULT result = m_channel->isPlaying(&bPlaying);
	ERRCHECKWITHEXIT(result);

	//CCLog("isPlaying %s\n", m_soundPath.c_str());

	return bPlaying;
}

FMOD_RESULT F_CALLBACK soundPlayCallback(FMOD_CHANNEL *channel,
		FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1,
		void *commanddata2) {

	if (type == FMOD_CHANNEL_CALLBACKTYPE_END) {

		FMOD::Channel* mychannel = (FMOD::Channel*) channel;

		KKAudioPlayer* player = NULL;

		mychannel->getUserData((void**) (&player));

		if (player) {
			player->onEndCallback();
		}
	}

	return FMOD_OK;
}

void KKAudioPlayer::play(int loop) {

	CCLog("play %s loop=%d,m_simple=%d\n", m_soundPath.c_str(), loop, m_simple);

	pSystem->update();

	if (m_sound == NULL) {
		load(m_soundPath.c_str());
	}

	if (loop == 0) {
		m_sound->setMode(FMOD_LOOP_OFF);
	} else {
		m_sound->setMode(FMOD_LOOP_NORMAL);
	}

	FMOD_RESULT result = pSystem->playSound(FMOD_CHANNEL_FREE, m_sound,
			!m_simple, m_simple ? NULL : &m_channel);

	if (!ERRCHECK(result) && !m_simple) {
		m_channel->setUserData(this);
		m_channel->setCallback(soundPlayCallback);
		m_channel->setLoopCount(loop);
		result = m_channel->setPaused(false);

	}

	m_loop = loop;
}

void KKAudioPlayer::rewind() {
	if (m_channel == NULL) {

		play(m_loop);

		return;
	}

	//printf("rewind %s loop=%d\n", m_soundPath.c_str(), m_loop);

	pSystem->update();

	if (isPlaying()) {

		FMOD_RESULT result = m_channel->setPosition(0, FMOD_TIMEUNIT_MS);
		ERRCHECKWITHEXIT(result);

	} else {

		play(m_loop);
	}
}

void KKAudioPlayer::stop() {

	//FIXME if channel is not and sound not null ,stop will not be stoped
	if (m_channel == NULL || m_sound == NULL) {
		return;
	}

	printf("stop %s\n", m_soundPath.c_str());

	FMOD_RESULT result;
	pSystem->update();

	KKCallback* callback = m_endCallback;

	m_endCallback = NULL;

	m_channel->setUserData(NULL);

	result = m_channel->stop();

	m_endCallback = callback;

	ERRCHECKWITHEXIT(result);
	m_channel = NULL;
}

void KKAudioPlayer::pause() {
	if (m_channel == NULL) {
		return;
	}
	pSystem->update();
	FMOD_RESULT result = m_channel->setPaused(true);
	ERRCHECKWITHEXIT(result);
}

void KKAudioPlayer::resume() {
	if (m_channel == NULL) {
		return;
	}
	pSystem->update();
	FMOD_RESULT result = m_channel->setPaused(false);
	ERRCHECKWITHEXIT(result);
}

void KKAudioPlayer::destory() {

	FMOD_RESULT result;
	pSystem->update();

	if (m_channel) {
		m_channel->setUserData(NULL);
		result = m_channel->stop();
		ERRCHECKWITHEXIT(result);
		m_channel = NULL;
	}

	if (m_sound) {
		result = m_sound->release();
		ERRCHECKWITHEXIT(result);
		m_sound = NULL;
	}

	m_soundPath.clear();

}

void KKAudioPlayer::setVolume(float volume) {
	if (m_channel == NULL) {
		return;
	}
	pSystem->update();
	FMOD_RESULT result = m_channel->setVolume(volume);
	ERRCHECKWITHEXIT(result);
}

float KKAudioPlayer::getVolume() {
	float fVolumn;
	if (m_channel == NULL) {
		return 0;
	}
	pSystem->update();
	FMOD_RESULT result = m_channel->getVolume(&fVolumn);
	ERRCHECKWITHEXIT(result);
	return fVolumn;
}

void KKAudioPlayer::setEndCallback(KKCallback* endCallback) {

	if (m_endCallback != endCallback) {
		if (m_endCallback) {
			m_endCallback->release();
		}

		m_endCallback = endCallback;

		if (m_endCallback) {
			m_endCallback->retain();
		}

	}

}

void KKAudioPlayer::onEndCallback() {
	if (m_endCallback) {
		m_endCallback->call(this);
	}
}
